package com.yu.blog.cofig.security.filter;

import com.alibaba.fastjson2.JSON;
import com.yu.blog.constant.ConstantData;
import com.yu.blog.enums.HttpStatusEnum;
import com.yu.blog.utils.JwtUtils;
import com.yu.blog.utils.RedisUtils.RedisUtils;
import com.yu.blog.utils.servletUtils.RequestUtil;
import com.yu.blog.utils.servletUtils.ResponseUtil;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtils redisUtils;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //如果是登录或者登出接口，直接放行
        if (ConstantData.LoginUrl.equals(request.getRequestURI()) || ConstantData.LogoutUrl.equals(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }
        //获取url最后的后缀名
        String extension = RequestUtil.getExtensionName(request);
        //swagger路径与静态资源放行
        if (ConstantData.SwaggerUrl.contains(request.getRequestURI()) || ConstantData.SourceList.contains(extension)) {
            filterChain.doFilter(request, response);
            return;
        }
        //白名单放行
        if (ConstantData.MyWhiteLists.contains(request.getRequestURI()) || ConstantData.SourceList.contains(extension)) {
            filterChain.doFilter(request, response);
            return;
        }

        //get方法白名单使用正则表达式放行
        if (request.getMethod().equals("GET")) {
            for(String list:ConstantData.MyWhiteLists)
            {
                if(Pattern.matches(list,request.getRequestURI()))
                {
                    filterChain.doFilter(request, response);
                    return;
                }
            }

        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(request, response);

        if (null != authentication) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
            filterChain.doFilter(request, response);
        } else {
            ResponseUtil.setFailedResponse(response, HttpStatusEnum.TOKEN_DENIED);
        }
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(jwtUtils.getJwtTokenHeader());
        if (!StringUtils.isEmpty(token)) {
            String username = jwtUtils.extractUsername(token);
            if (!StringUtils.isEmpty(username)) {
                String grantedAuthorities = (String) redisUtils.get("user:" + username + ":role");
                if (!StringUtils.isEmpty(grantedAuthorities)) {
                    List<Map> mapList = JSON.parseArray(grantedAuthorities, Map.class);
                    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
                    for (Map map : mapList) {
                        String auth = (String) map.get("authority");
                        authorities.add(new SimpleGrantedAuthority("ROLE_" + auth));
                    }
                    return new UsernamePasswordAuthenticationToken(username, null, authorities);
                }
                return null;
            } else {
                String flushToken = request.getHeader(jwtUtils.getJwtRefreshTokenHeader());
                if (!StringUtils.isEmpty(flushToken)) {
                    String flushUsername = jwtUtils.extractUsername(flushToken);
                    if (!StringUtils.isEmpty(flushUsername)) {
                        String role = (String) redisUtils.get("user:" + flushUsername + ":role");
                        if (!StringUtils.isEmpty(role)) {
                            String jwtToken = jwtUtils.generateToken(flushUsername);
                            String newFlushToken = jwtUtils.createRefreshToken(flushUsername);
                            response.setHeader(jwtUtils.getJwtTokenHeader(), jwtToken);
                            response.setHeader(jwtUtils.getJwtRefreshTokenHeader(), newFlushToken);
                            //刷新redis过期时间
                            redisUtils.expire("user:" + newFlushToken + ":role", jwtUtils.getExpirationRefreshTime() * 60 * 60 * 24);
                            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
                            authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
                            return new UsernamePasswordAuthenticationToken(flushUsername, null, authorities);
                        }
                    }
                }
            }
        }
        return null;
    }
}
